﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MetadataBasedConfig.Framework;
using MetadataBasedConfig.Framework.Model;
using System.Data.Objects.DataClasses;
using System.Data.Objects;

namespace MetadataBasedConfig.EntityModel
{
    public class EntityConfigMetadataProvider : IConfigMetadataProvider
    {
        private MDAEntities _entities;
        private Dictionary<Type, Func<MDAEntities, object>> entityObjectSetDictionary = new Dictionary<Type, Func<MDAEntities, object>>(); 

        #region Ctor

        private ObjectSet<T2> GetObjectSet<T1,T2>()
            where T2:class,T1
        {
            if (entityObjectSetDictionary.ContainsKey(typeof(T1)))
            {
                return entityObjectSetDictionary[typeof(T1)](_entities) as ObjectSet<T2>;
            }
            return null;
        }

        public EntityConfigMetadataProvider(MDAEntities entities)
        {
            _entities = entities;
            
            entityObjectSetDictionary.Add(typeof(IConfigMeta), e=>e.ConfigMetas);
            entityObjectSetDictionary.Add(typeof(IConfigMetaConfigInfo), e => e.ConfigMetaConfigInfoes);
            entityObjectSetDictionary.Add(typeof(IConfigMetaConfigInfoData), e => e.ConfigMetaConfigDatas);
            entityObjectSetDictionary.Add(typeof(IConfigMetaConfigInfoProperty), e => e.ConfigMetaConfigInfoProperties);
            entityObjectSetDictionary.Add(typeof(IConfigMetaRelation), e => e.ConfigMetaRelations);
            entityObjectSetDictionary.Add(typeof(IConfigMetaRelationType), e => e.ConfigMetaRelationTypes);
            entityObjectSetDictionary.Add(typeof(IConfigMetaType), e => e.ConfigTypes);
             
        }
            
        #endregion

        #region Implement IConfigMetadataProvider interface

        public IConfigMeta GetConfigMeta(string configMetaTypeModelKey, string content)
        {
            var all = (from c in _entities.ConfigMetas
                    where c.ConfigType1.Name == configMetaTypeModelKey && c.Content == content
                    select c).ToList();
            if (all.Count > 1)
                throw new InvalidOperationException();
            return all.FirstOrDefault();
        }

        public IEnumerable<IConfigMetaConfigInfo> GetConfigInfos(long configMetaModelKey)
        {
            return (from c in _entities.ConfigMetaConfigInfoes.IncludeStaticConstraint()
                    where c.ConfigMeta1.ID == configMetaModelKey
                    select c).ToList();
        }

        public IEnumerable<IConfigMetaConfigInfoData> GetConfigMetaConfigDatasOfMetaInfo(long configInfoModelKey, long dataID)
        {
            return (from c in _entities.ConfigMetaConfigDatas.IncludeStaticConstraint()
                    where c.ConfigInfo == configInfoModelKey && c.DataID == dataID
                    select c).ToList();
        }

        public T2 CreateMetadata<T1, T2>()
            where T2 : class,T1
        {
            ObjectSet<T2> objectSet = GetObjectSet<T1, T2>();
            return objectSet != null ? objectSet.CreateObject() : null;
        }


        public T2 CreateMetadata<DataKeyType, T2>(DataKeyType key) 
            where T2 : class, IDataKeyModel<DataKeyType>
        {
            IDataKeyModel<DataKeyType> dataKeyModel = CreateMetadata<IDataKeyModel<DataKeyType>, T2>();
            return (T2)(dataKeyModel.GetModel(key));
        }

        #endregion


        #region IConfigMetadataProvider Members


        public void AddMetadata<T1, T2>(T1 metadata)
            where T2 : class,T1
        {
            if (metadata is T2 )
            {
                ObjectSet<T2> objectSet = GetObjectSet<T1, T2>();
                if (objectSet != null)
                    objectSet.AddObject(metadata as T2);
            }
        }

        public void Save()
        {
            _entities.SaveChanges();
        }

        public void DeleteMetadata<T1, T2>(T1 metadata)
            where T2 : class,T1
        {
            if (metadata is T2)
            {
                ObjectSet<T2> objectSet = GetObjectSet<T1, T2>();
                if (objectSet != null)
                    objectSet.DeleteObject(metadata as T2);
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            _entities.Dispose();
        }

        #endregion

        #region Other Methods

        public void Save(SaveOptions saveOptions)
        {
            _entities.SaveChanges(saveOptions);
        }

        #endregion



    }
}
